home *** CD-ROM | disk | FTP | other *** search
- /*
- TCP Client/Server Queuing Example
- Steve Falkenburg, MacDTS, Apple Computer
- 3/11/92
-
- this client/server sample uses MacTCP to implement a simple "greeting" server. the server
- opens up several listeners on kGreetingPort (1235). when a client connects, the data entered
- in the greeting dialog is sent to the remote connection, and the connection is closed.
-
- connection management is done through the use of Operating System queues to simplify tracking
- and usage.
- */
-
-
- #include <Processes.h>
- #include <MacTCPCommonTypes.h>
- #include <TCPPB.h>
-
- #include "const.h"
- #include "globals.h"
- #include "utils.h"
- #include "queues.h"
- #include "network.h"
-
- void StartListener(TCPiopb *pBlock);
- void ListenerCompletion(MyQElemPtr iopb);
- void SendData(TCPiopb *pBlock,StringPtr data);
-
-
- /* initialize TCP/IP driver and create our queues, putting them on the unused list
- */
-
- OSErr InitNetwork(void)
- {
- OSErr err;
- TCPiopb *pBlock;
- short i;
-
- err = OpenDriver("\p.ipp",&gTcpDrvrRef);
- if (err!=noErr)
- return err;
-
- for (i=0; i<kNumConnections; i++) {
- pBlock = (TCPiopb *)GetUnusedPBlock();
- if (pBlock)
- StartListener(pBlock);
- }
-
- return noErr;
- }
-
-
- /* creates a connection end and assigns it to listen for an incoming connection on our
- network port.
- */
-
- void StartListener(TCPiopb *pBlock)
- {
- Ptr rcvBuff;
- OSErr err;
-
- rcvBuff = NewPtr(kRcvBuffSize);
- if (MemError()!=noErr)
- DoError(MemError());
-
- /* create a network stream */
-
- pBlock->csCode = TCPCreate;
- pBlock->ioCRefNum = gTcpDrvrRef;
- pBlock->csParam.create.rcvBuff = rcvBuff;
- pBlock->csParam.create.rcvBuffLen = kRcvBuffSize;
- pBlock->csParam.create.notifyProc = nil;
- err = PBControl(pBlock,false);
- if (err!=noErr)
- DoError(err);
-
- /* create a listener */
-
- pBlock->csCode = TCPPassiveOpen;
- #ifdef __SYSEQU__
- ((MyQElemPtr)pBlock)->savedA5 = *(long *)CurrentA5;
- #else
- ((MyQElemPtr)pBlock)->savedA5 = (long)CurrentA5;
- #endif
- pBlock->ioCompletion = (ProcPtr)ListenerCompletion;
- pBlock->csParam.open.ulpTimeoutValue = 0;
- pBlock->csParam.open.ulpTimeoutAction = 1;
- pBlock->csParam.open.validityFlags = 0xC0;
- pBlock->csParam.open.commandTimeoutValue = 0;
- pBlock->csParam.open.remoteHost = 0;
- pBlock->csParam.open.remotePort = 0;
- pBlock->csParam.open.localHost = 0;
- pBlock->csParam.open.localPort = kGreetingPort;
- pBlock->csParam.open.tosFlags = 0;
- pBlock->csParam.open.precedence = 0;
- pBlock->csParam.open.dontFrag = 0;
- pBlock->csParam.open.timeToLive = 0;
- pBlock->csParam.open.security = 0;
- pBlock->csParam.open.optionCnt = 0;
- PBControl(pBlock,true);
-
- gRunning++; // increment count of running parameter blocks
- }
-
-
- /* called to release all network resources in response to a quit
- */
-
- void CloseNetwork(void)
- {
- THz theZone;
- short drvrRefNum;
- OSErr err;
- TCPiopb tcpBlock;
- StreamPtr *curStream;
- long theStream;
-
- theZone = ApplicZone();
-
- tcpBlock.ioCRefNum = gTcpDrvrRef;
- tcpBlock.csCode = TCPGlobalInfo;
- err = PBControl((ParmBlkPtr)&tcpBlock,false);
- if (err!=noErr)
- return;
-
- curStream = *tcpBlock.csParam.globalInfo.tcpCDBTable;
- while (*curStream) {
-
- theStream = *curStream;
-
- if (PtrZone((Ptr)theStream)==theZone) { // only release streams in our heap
-
- tcpBlock.csCode = TCPStatus;
- tcpBlock.tcpStream = theStream;
- err = PBControl((ParmBlkPtr)&tcpBlock,false);
-
- // abort connection
-
- tcpBlock.csCode = TCPAbort;
- tcpBlock.tcpStream = theStream;
- err = PBControl((ParmBlkPtr)&tcpBlock,false);
-
- // release stream
-
- tcpBlock.csCode = TCPRelease;
- tcpBlock.tcpStream = theStream;
- err = PBControl((ParmBlkPtr)&tcpBlock,false);
- }
-
- curStream++;
- }
- }
-
-
- /* this completion routine will be called when one of the listeners gets a connection from a
- remote machine. since we're using OS queues dispatched from the main event loop, we just
- take the parameter block and put it on the completed queue. if running seven, we call
- WakeUpProcess() to return control to the application
- */
-
- void ListenerCompletion(MyQElemPtr iopb)
- {
- long saveA5;
- ProcessSerialNumber currentProc;
-
- saveA5 = SetA5(iopb->savedA5);
-
- StoreCompletedPBlock(iopb);
- gRunning--;
-
- if (gRunningSeven) {
- WakeUpProcess(&gOurPSN);
- }
-
- SetA5(saveA5);
- }
-
-
- /* this routine is called from the event dispatcher of the event loop to continue processing
- of completed listens received at interrupt time from ListenerCompletion. We send them
- some data, close the connection, and restart the listener, putting it back on MacTCP's queue
- */
-
- void ProcessConnection(MyQElemPtr iopb)
- {
- SendData(&iopb->tcpBlock,gGreetingData);
- RecycleFreePBlock(iopb);
- iopb = GetUnusedPBlock();
- if (iopb)
- StartListener(&iopb->tcpBlock);
- }
-
-
- /* here, we send some data to the remote host over the opened connection and close the connection
- when done. if we didn't use os queues, this code would be much more complicated, since it
- would have to be interrupt safe, and we would have to perform all driver calls async with
- linked completion routines (yuck)
- */
-
- void SendData(TCPiopb *pBlock,StringPtr data)
- {
- OSErr err;
- wdsEntry wdsPtr[4];
- char crlf[] = "\015\012";
-
- wdsPtr[0].length = wdsPtr[2].length = 2;
- wdsPtr[0].ptr = wdsPtr[2].ptr = crlf;
- wdsPtr[1].length = data[0];
- wdsPtr[1].ptr = (void *)&data[1];
- wdsPtr[3].length = 0;
- wdsPtr[3].ptr = nil;
-
- pBlock->csCode = TCPSend;
- pBlock->ioCRefNum = gTcpDrvrRef;
- pBlock->csParam.send.ulpTimeoutValue = 0;
- pBlock->csParam.send.ulpTimeoutAction = 1;
- pBlock->csParam.send.validityFlags = 0xc0;
- pBlock->csParam.send.pushFlag = false;
- pBlock->csParam.send.urgentFlag = false;
- pBlock->csParam.send.wdsPtr = (Ptr)wdsPtr;
- err = PBControl(pBlock,false);
- if (err!=noErr)
- DoError(err);
-
- pBlock->csCode = TCPClose;
- pBlock->ioCRefNum = gTcpDrvrRef;
- pBlock->csParam.close.validityFlags = 0xC0;
- pBlock->csParam.close.ulpTimeoutValue = 20;
- pBlock->csParam.close.ulpTimeoutAction = 1;
- err = PBControl(pBlock,false);
- if (err!=noErr)
- DoError(err);
-
- pBlock->csCode = TCPRelease;
- pBlock->ioCRefNum = gTcpDrvrRef;
- err = PBControl(pBlock,false);
- if (err!=noErr)
- DoError(err);
- }
-